package com.google.code.guava.reflect.predicate;

import static com.google.code.guava.reflect.predicate.ClassQualifiersPredicate.newClassQualifiersPredicate;
import static com.google.code.guava.reflect.predicate.Qualifier.ABSTRACT;
import static com.google.code.guava.reflect.predicate.Qualifier.INTERFACE;
import static com.google.code.guava.reflect.predicate.Qualifier.concat;

import com.google.common.base.Predicate;

public final class ClassPredicates{

    private static enum FixedClassPredicate implements Predicate<Class<?>>{
        INNER_CLASSES{

            public boolean apply(final Class<?> input){
                return input.isMemberClass();
            }
        },
        ANONYMOUS_CLASSES{

            public boolean apply(final Class<?> input){
                return input.isAnonymousClass();
            }
        },
        LOCAL_CLASSES{

            public boolean apply(final Class<?> input){
                return input.isLocalClass();
            }
        },
        TOP_LEVEL{

            public boolean apply(final Class<?> input){
                return input.getEnclosingClass() == null;
            }

        },
        ARRAY_CLASSES{

            public boolean apply(final Class<?> input){
                return input.isArray();
            }
        },
        MULTI_ARRAY_CLASSES{

            public boolean apply(final Class<?> input){

                return input.isArray() && input.getComponentType()
                .isArray();
            }
        }

    }

    public static Predicate<Class<?>> forAbstractClasses(){
        return withAnyQualifiers(ABSTRACT);
    }

    public static Predicate<Class<?>> forArrayClasses(){
        return FixedClassPredicate.ARRAY_CLASSES;
    }

    public static Predicate<Class<?>> forInnerClasses(){
        return FixedClassPredicate.INNER_CLASSES;
    }

    public static Predicate<Class<?>> forInterfaces(){
        return withAnyQualifiers(INTERFACE);
    }

    public static Predicate<Class<?>> forLocalClasses(){
        return FixedClassPredicate.LOCAL_CLASSES;
    }

    public static Predicate<Class<?>> forMultiDimensionalArrayClasses(){
        return FixedClassPredicate.MULTI_ARRAY_CLASSES;
    }

    public static Predicate<Class<?>> withAllQualifiers(
        final Qualifier qualifier, final Qualifier ... qualifiers){

        return newClassQualifiersPredicate(concat(qualifier, qualifiers),
            QualifierEvalutionStrategy.CONTAINS_ALL);

    }

    public static Predicate<Class<?>> withAnyQualifiers(
        final Qualifier qualifier, final Qualifier ... qualifiers){

        return newClassQualifiersPredicate(concat(qualifier, qualifiers),
            QualifierEvalutionStrategy.CONTAINS_ANY);

    }

    public static Predicate<Class<?>> withoutQualifiers(
        final Qualifier qualifier, final Qualifier ... qualifiers){
        return newClassQualifiersPredicate(concat(qualifier, qualifiers),
            QualifierEvalutionStrategy.CONTAINS_NONE);
    }

    private ClassPredicates(){}

}
